package stardust.product.platform.webc.spi.servlet;


import java.io.IOException;
import java.io.InputStream;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import stardust.product.platform.webc.WebcConfig;
import stardust.product.platform.webc.WebcContext;
import stardust.product.platform.webc.WebcException;
import stardust.product.platform.webc.support.WebcContextUtils;


public class WebcDispatchFilter implements Filter
{

  public static final String PARAM_WEBC_CONFIG = "config";

  private FilterConfig config;

  private String webcConfig;

  private WebcContext webcContext;

  public void init(FilterConfig config) throws ServletException
  {
    this.config = config;
    this.webcConfig = this.config.getInitParameter(WebcDispatchFilter.PARAM_WEBC_CONFIG);
    this.webcConfig = this.webcConfig == null ? this.webcConfig : this.webcConfig.trim();

    InputStream configStream = this.config.getServletContext().getResourceAsStream(this.webcConfig);

    if (configStream == null)
    {
      throw new ServletException("无法加载WebcContext配置文件[" + this.webcConfig + " -> " + this.config.getServletContext().getRealPath(this.webcConfig) + "]。");
    }

    WebcConfig webcConfig = new WebcConfig(configStream);

    if ((webcConfig.getContextName() == null || webcConfig.getContextName().trim().isEmpty()) && WebcContextUtils.getDefaultContext() != null)
    {
      // 多实例共享默认上下文。
      this.webcContext = WebcContextUtils.getDefaultContext();
    }
    else
    {
      // 构造拥有独立配置和限定名的上下文。
      this.webcContext = new WebcContext(webcConfig);
    }
  }

  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
  {
    HttpServletRequest request;
    HttpServletResponse response;
    
    if (req instanceof HttpServletRequest && res instanceof HttpServletResponse)
    {
      request = (HttpServletRequest) req;
      response = (HttpServletResponse) res;

      if (this.webcContext.getConfig().getParameter().get(WebcConfig.CFG_CHARACTER_ENCODING) != null)
      {
        request.setCharacterEncoding(this.webcContext.getConfig().getParameter().get(WebcConfig.CFG_CHARACTER_ENCODING));
        response.setCharacterEncoding(this.webcContext.getConfig().getParameter().get(WebcConfig.CFG_CHARACTER_ENCODING));
      }

      /*
       * 计算URI访问地址。
       */
      String contextPath = this.config.getServletContext().getContextPath();
      String uri;

      if (contextPath.equals("/"))
      {
        uri = request.getRequestURI();
      }
      else
      {
        uri = request.getRequestURI().substring(contextPath.length());
      }

      uri = uri.startsWith("/") ? uri : "/" + uri;
      uri = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
      uri = uri.isEmpty() ? "/" : uri;

      try
      {
        if (this.webcContext.hasInvoker(uri))
        {
          /*
           * 将资源URI递交给WebcContext继续处理。
           */
          this.webcContext.invoke(uri, new ServletWebcRequestHandler(this.webcContext, request, response));
          return;
        }
      }
      catch(WebcException ex)
      {
        throw ex;
      }
      catch(Throwable ex)
      {
        throw new ServletException(ex);
      }
    }

    chain.doFilter(req, res);
  }

  public void destroy()
  {
    this.config = null;
  }

}
